const parse = require("parseurl");
const methods = require("methods");
const Route = require("./route");
const Layer = require("./layer");
function Router() {
  let router = (req, res, next) => {
    router.handle(req, res, next);
  };
  router.stack = [];
  router.__proto__ = proto;
  // 发布订阅模式，收集订阅者
  router.paramsCallback = {};
  return router;
}
let proto = {};
proto.param = function (key, handler) {
  if (this.paramsCallback[key]) {
    // 如果{id: [fn]}存在的话，则往id的数组中push handler
    this.paramsCallback[key].push(handler);
  } else {
    // 不存在 {id:[Fn, Fn], name:[Fn]}
    this.paramsCallback[key] = [handler];
  }
};

proto.route = function (path) {
  let route = new Route();
  let layer = new Layer(path, route.dispatch.bind(route)); //给调用方法放入 一层layer
  layer.route = route; //每个层都有route属性, 没有route属性的是中间件
  this.stack.push(layer);
  return route;
};

proto.use = function (path, handler) {
  if (typeof path == "function") {
    handler = path;
    path = "/";
  }
  let layer = new Layer(path, handler);
  layer.route = undefined; //layer的route属性为undefined，说明是中间件
  this.stack.push(layer);
};

methods.forEach((method) => {
  proto[method] = function (path, handlers) {
    let route = this.route(path);
    route[method](handlers);
  };
});
proto.process_params = function (layer, req, res, done) {
  if (!layer.keys || layer.keys.length === 0) {
    return done;
  }
  let keys = layer.keys.map((item) => item.name);
  let params = this.paramsCallback;
  // console.log(keys, params);
  let idx = 0;
  function next() {
    if (keys.length === idx) return done();
    let key = keys[idx++];
    // 创建一个执行订阅者的函数
    processCallback(key, next);
  }
  next();
  function processCallback(key, out) {
    let fns = params[key];
    if (!fns) return out();
    let idx = 0;
    let value = req.params[key];
    function next() {
      if (fns.length === idx) return out();
      let fn = fns[idx++];
      fn(req, res, next, value, key);
    }
    next();
  }
};
// 从Application处接收到请求，开始处理路由请求，对应Application的31行
proto.handle = function (req, res, out) {
  let { pathname } = parse(req);
  let idx = 0;
  let removed = "";
  // express 核心，通过next函数控制向下执行，进行迭代操作
  const dispatch = (err) => {
    if (idx === this.stack.length) return out();
    if (removed) {
      req.url = removed + req.url;
      removed = "";
    }
    let layer = this.stack[idx++];
    if (err) {
      // 传入错误属性
      if (!layer.route && layer.handler.length === 4) {
        // 是中间件,处理函数参数必须4个,才是处理的错误中间件
        // layer.handler.length === 4;
        layer.handle_error(err, req, res, dispatch);
      } else {
        // 是路由
        dispatch(err);
      }
    } else {
      // 对路由或中间件进行区别处理
      if (layer.match(pathname)) {
        // TO 首先对路径进行匹配
        if (!layer.route && layer.handler.length !== 4) {
          // 如果路径不是/,说明是中间件的路径，进行匹配时需要删除
          if (layer.path !== "/") {
            removed = req.url;
            req.url = removed.slice(layer.path.length);
          }
          //中间件,这里不能执行错误中间件
          layer.handle_request(req, res, dispatch);
        } else {
          // 路由, 并且方法能够匹配上
          if (layer.route.methods[req.method.toLowerCase()]) {
            req.params = layer.params;
            // 将订阅好的事件 依次执行
            this.process_params(layer, req, res, () => {
              layer.handle_request(req, res, dispatch);
            });
          } else {
            dispatch();
          }
        }
      } else {
        dispatch();
      }
    }
  };
  dispatch();
};
module.exports = Router;
